1 module d_tree_sitter.tree_cursor;
2 
3 extern (C):
4 
5 import d_tree_sitter.node;
6 
7 import std.exception : enforce;
8 import std..string : fromStringz;
9 
10 /// A stateful object for walking a syntax `Tree` efficiently.
11 struct TreeCursor
12 {
13   import d_tree_sitter.libc : TSTreeCursor, ts_tree_cursor_copy,
14     ts_tree_cursor_current_node, ts_tree_cursor_current_field_id,
15     ts_tree_cursor_current_field_name, ts_tree_cursor_goto_first_child,
16     ts_tree_cursor_goto_parent,
17     ts_tree_cursor_goto_next_sibling, ts_tree_cursor_goto_first_child_for_byte,
18     ts_tree_cursor_reset, ts_tree_cursor_delete;
19 
20   /** internal `TSTreeCursor` */
21   TSTreeCursor tstreecursor;
22 
23   /** Create a new tree cursor */
24   this(TSTreeCursor tstreecursor) @nogc nothrow
25   {
26     this.tstreecursor = tstreecursor;
27   }
28 
29   ~this() @nogc nothrow
30   {
31     return ts_tree_cursor_delete(&tstreecursor);
32   }
33 
34   /** Copy a tree cursor */
35   this(ref return scope TreeCursor otherTreeCursor) @nogc nothrow
36   {
37     this.tstreecursor = ts_tree_cursor_copy(&otherTreeCursor.tstreecursor);
38   }
39 
40   /** Copy a tree cursor */
41   this(TreeCursor* otherTreeCursor) @nogc nothrow
42   {
43     this.tstreecursor = ts_tree_cursor_copy(&otherTreeCursor.tstreecursor);
44   }
45 
46   @disable this(this); // disable postblit
47 
48   /** Get the tree cursor's current [Node]. */
49   auto node() const @nogc nothrow
50   {
51     return Node(ts_tree_cursor_current_node(&tstreecursor));
52   }
53 
54   /**
55     Get the numerical field id of this tree cursor's current node.
56 
57     See also [field_name](TreeCursor::field_name).
58   */
59   auto field_id() const @nogc
60   {
61     auto id = ts_tree_cursor_current_field_id(&tstreecursor);
62     assert(id != 0, "id is 0.");
63     return id;
64   }
65 
66   /** Get the field name of this tree cursor's current node. */
67   auto field_name() const @nogc nothrow
68   {
69     return fromStringz(ts_tree_cursor_current_field_name(&tstreecursor));
70   }
71 
72   /**
73     Move this cursor to the first child of its current node.
74 
75     This returns `true` if the cursor successfully moved, and returns `false`
76     if there were no children.
77   */
78   auto goto_first_child() @nogc nothrow
79   {
80     return ts_tree_cursor_goto_first_child(&tstreecursor);
81   }
82 
83   /**
84     Move this cursor to the parent of its current node.
85 
86     This returns `true` if the cursor successfully moved, and returns `false`
87     if there was no parent node (the cursor was already on the root node).
88   */
89   auto goto_parent() @nogc nothrow
90   {
91     return ts_tree_cursor_goto_parent(&tstreecursor);
92   }
93 
94   /**
95      Move this cursor to the next sibling of its current node.
96 
97      This returns `true` if the cursor successfully moved, and returns `false`
98      if there was no next sibling node.
99   */
100   auto goto_next_sibling() @nogc nothrow
101   {
102     return ts_tree_cursor_goto_next_sibling(&tstreecursor);
103   }
104 
105   /**
106     Move this cursor to the first child of its current node that extends beyond
107     the given byte offset.
108 
109     This returns the index of the child node if one was found, and returns `None`
110     if no such child was found.
111   */
112   auto goto_first_child_for_byte(size_t index)
113   {
114     auto result = ts_tree_cursor_goto_first_child_for_byte(&tstreecursor, cast(uint) index);
115     enforce(result >= 0, "result is less than 0.");
116     return result;
117   }
118 
119   /** Re-initialize this tree cursor to start at a different node. */
120   auto reset(Node node) @nogc nothrow
121   {
122     return ts_tree_cursor_reset(&tstreecursor, node.tsnode);
123   }
124 }